package com.whfp.afs330h_sdk.utils;

import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import com.blankj.utilcode.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加密解密工具类
 */
public final class AESUtils {

    private static final String AES_MODE = "AES/CBC/PKCS7Padding";
    private static final String CHARSET = "UTF-8";
    private static final String CIPHER = "AES";
    private static final String HASH_ALGORITHM = "SHA-256";
    private static final byte[] IV_BYTES = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    //====================================================秘钥区=============================================================
    //试剂卡条码起始位加密秘钥（原文是臻稀生物，转为了16进制得到的此秘钥）
    private static final String QSW_key = "e887bbe7a880e7949fe789a9";
    //设备型号和MAC地址加解密秘钥
    private static final String device_key = "zenith-bio";
    //用于加密HTTP地址相关的加解密秘钥（原文是zenith-bio，转为了16进制得到的此秘钥）
    private static final String http_key = "7a656e6974682d62696f";
    //用于加解密AFS330H设备的客户代码的秘钥（原文是AFS330H，转为了16进制得到的此秘钥）
    private static final String afs330h_key = "41465333333048";
    //用于测试加密功能的秘钥
    private static final String test_key = "123456";
    //====================================================秘钥区=============================================================

    /**
     * Generates SHA256 hash of the password which is used as key
     *
     * @param password used to generated key
     * @return SHA256 of the password
     */
    private static SecretKeySpec generateKey(final String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        final MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
        byte[] bytes = password.getBytes(CHARSET);
        digest.update(bytes, 0, bytes.length);
        byte[] key = digest.digest();

        return new SecretKeySpec(key, CIPHER);
    }


    /**
     * Encrypt and encode message using 256-bit AES with key generated from password.
     *
     * @param password used to generated key
     * @param message  the thing you want to encrypt assumed String UTF-8
     * @return Base64 encoded CipherText
     * @throws GeneralSecurityException if problems occur during encryption
     */
    public static String encrypt(final String password, String message)
            throws GeneralSecurityException {

        try {
            final SecretKeySpec key = generateKey(password);
            byte[] cipherText = encrypt(key, IV_BYTES, message.getBytes(CHARSET));
            //NO_WRAP is important as was getting \n at the end
            return Base64.encodeToString(cipherText, Base64.NO_WRAP);
        } catch (UnsupportedEncodingException e) {
            throw new GeneralSecurityException(e);
        }
    }


    /**
     * More flexible AES encrypt that doesn't encode
     *
     * @param key     AES key typically 128, 192 or 256 bit
     * @param iv      Initiation Vector
     * @param message in bytes (assumed it's already been decoded)
     * @return Encrypted cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    public static byte[] encrypt(final SecretKeySpec key, final byte[] iv, final byte[] message)
            throws GeneralSecurityException {
        final Cipher cipher = Cipher.getInstance(AES_MODE);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

        return cipher.doFinal(message);
    }


    /**
     * Decrypt and decode ciphertext using 256-bit AES with key generated from password
     *
     * @param password                used to generated key
     * @param base64EncodedCipherText the encrpyted message encoded with base64
     * @return message in Plain text (String UTF-8)
     * @throws GeneralSecurityException if there's an issue decrypting
     */
    public static String decrypt(final String password, String base64EncodedCipherText)
            throws GeneralSecurityException {

        try {
            final SecretKeySpec key = generateKey(password);
            byte[] decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP);
            byte[] decryptedBytes = decrypt(key, IV_BYTES, decodedCipherText);
            return new String(decryptedBytes, CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new GeneralSecurityException(e);
        }
    }

    /**
     * More flexible AES decrypt that doesn't encode
     *
     * @param key               AES key typically 128, 192 or 256 bit
     * @param iv                Initiation Vector
     * @param decodedCipherText in bytes (assumed it's already been decoded)
     * @return Decrypted message cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    public static byte[] decrypt(final SecretKeySpec key, final byte[] iv, final byte[] decodedCipherText)
            throws GeneralSecurityException {
        final Cipher cipher = Cipher.getInstance(AES_MODE);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
        return cipher.doFinal(decodedCipherText);
    }

    /**
     * 获取设备AFS330H的客户代码
     *
     * @return
     */
    public static int getAfs330hClientCode() {
        String s = null;
        try {
            s = decrypt(afs330h_key, "xVJSRRMFqoPDONlDxMG6pA==");
            Log.i("AFS330H的客户代码解密：", s);
            return Integer.parseInt(s);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            Log.i("AFS330H的客户代码解密出错：", e.toString());
        }
        return -1;
    }

    /**
     * 加密设备MAC地址
     *
     * @param str
     * @return
     */
    public static String encryptDeviceMac(String str) throws GeneralSecurityException {
        String s = encrypt(device_key, str);
        Log.i("加密：", str);
        return s;
    }

    /**
     * 解密设备MAC地址
     *
     * @param str
     * @return
     */
    public static String decryptDeviceMac(String str) throws GeneralSecurityException {
        String s = decrypt(device_key, str);
        Log.i("解密：", s);
        return s;
    }

    /**
     * 检测设备【破冰2】的二维码解密
     *
     * @param str 扫描破冰2设备上的二维码得来的密文
     * @return 破冰2的蓝牙mac地址
     */
    public static String decryptDeviceMacByPB_2(String str) {
        //第一步：判断是否是“@@”分割的字符串
        if (TextUtils.isEmpty(str) || !RxUtils.contains(str, "@@")) {
            Log.e("tag", "二维码不合规：没有包含@@分隔符或为空");
            return null;
        }
        //第二步：尝试解密通过“@@”截取出来的前段密文
        String s;
        try {
            String ycl = str.substring(0, str.indexOf("@@"));
            Log.i("tag", "截取出来的预处理密文：" + ycl);
            s = decryptDeviceMac(ycl);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("tag", "破冰2二维码解密出错：" + e.toString());
            return null;
        }
        //第三步：判断解密出来的明文长度是否合规
        if (StringUtils.isEmpty(s) || s.length() != 24) {
            Log.e("tag", "破冰2二维码解密出的明文长度不合规");
            return null;
        }
        //第四步：判断是否是属于破冰2的二维码(判断方法为比对明文前7为的字符串是否是“PB-01M2”)
        String xh = s.substring(0, 7);
        String mac = s.substring(7, s.length());
        Log.i("tag", "这是啥？" + s + "型号：" + xh + "地址：" + mac);
        if (!xh.equals("PB-01M2")) {
            Log.e("tag", "不是破冰2的型号");
            return null;
        }
        //第五步：判断是否是正确的MAC地址
        if (!RxUtils.isMac(mac)) {
            Log.e("tag", "MAC地址不正确");
            return null;
        }
        return mac;
    }

    /**
     * 加密试剂卡条码起始位
     *
     * @param str
     * @return
     */
    public static String encryptQSW(String str) throws GeneralSecurityException {
        String s = encrypt(QSW_key, str);
        Log.i("加密：", s);
        return s;
    }

    /**
     * 解密试剂卡条码起始位
     *
     * @param str
     * @return
     */
    public static String decryptQSW(String str) throws GeneralSecurityException {
        String s = decrypt(QSW_key, str);
        Log.i("解密：", s);
        return s;
    }

    /**
     * 加密HTTP相关
     *
     * @param str
     * @return
     */
    public static String encryptHttp(String str) throws GeneralSecurityException {
        String s = encrypt(http_key, str);
        Log.i("加密：", s);
        return s;
    }

    /**
     * 解密HTTP相关
     *
     * @param str
     * @return
     */
    public static String decryptHttp(String str) throws GeneralSecurityException {
        String s = decrypt(http_key, str);
        Log.i("解密：", s);
        return s;
    }


    /**
     * 测试加密
     *
     * @param str
     * @return
     */
    public static String encryptTest(String str) throws GeneralSecurityException {
        String s = encrypt(test_key, str);
        Log.i("加密：", s);
        return s;
    }

    /**
     * 测试解密
     *
     * @param str
     * @return
     */
    public static String decryptTest(String str) throws GeneralSecurityException {
        String s = decrypt(test_key, str);
        Log.i("解密：", s);
        return s;
    }

}
